package com.mine.androidlearn;

import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.log4j.LogConfigurator;
import android.text.TextUtils;
import android.util.Log;

import com.mine.androidlearn.common.crash.CrashHandler;
import com.mine.androidlearn.common.crash.CrashListenerAdapter;
import com.mine.androidlearn.common.util.Utils;
import com.mine.androidlearn.tempmvp.MainActivity;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

import org.apache.log4j.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Application
 *
 * @author: hujianghao5
 * @version: V1.0 2018/8/1 10:25
 */
public class GlobalApplication extends Application{

    private static final String TAG = "GlobalApplication";
    private static Logger sLogger;

    private static RefWatcher mRefWatcher;

    /**
     * 获取LeakCanary内存泄漏监视器
     *
     * @return
     */
    public static RefWatcher getRefWatcher() {
        return mRefWatcher;
    }

    private static final String LOGIN = MainActivity.class.getSimpleName();//用来崩溃时候重新启动APP用，启动界面
    private ActivityLifecycle mLifecycle = new ActivityLifecycle();//监控Activity生命周期


    private final static ReentrantLock lock = new ReentrantLock();//读写锁来控制堆栈的修改。
    /*保存所有的已打开的Activity*/
    private final static ConcurrentHashMap<String, WeakReference<? extends Activity>> map = new ConcurrentHashMap<>();


    private String lastLaunched;// 最近打开的Activity


    @Override
    public void onCreate() {
        super.onCreate();

        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        mRefWatcher = LeakCanary.install(this);

        registerActivityLifecycleCallbacks(mLifecycle);//注册
        map.clear();

        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(this);
        crashHandler.setStoreFile(true);
        crashHandler.setCrashListener(new CrashListenerAdapter() {
            @Override
            public void handleException(Throwable throwable) {
                super.handleException(throwable);
                sLogger.error(Utils.getCrashInfo(throwable));
            }

            @Override
            public void beforeKillProcess() {
                super.beforeKillProcess();
                sLogger.info(Runtime.getRuntime().totalMemory() + "/" + Runtime.getRuntime().maxMemory() + "/" + Runtime.getRuntime().freeMemory());
                unregisterActivityLifecycleCallbacks(mLifecycle);//取消注册
//                sendBroadcast(new Intent(Constant.ACTION_APPLICATION_CRASH));//非必需
                finishAllActivities();
//                stopService();//非必需
                if (TextUtils.isEmpty(lastLaunched) || !lastLaunched.equals(LOGIN)) {     // 如果崩溃不是发生在登录页面才启动登录页面，避免陷入死循环
                    startLoginActivity();
                }
            }
        });

        log4jConfigure(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
    }
    private void startLoginActivity() {
        /*看需要修改启动界面*/
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

    /**
     * 日志记录框架
     *
     * @param useFileAppender
     */
    private synchronized void log4jConfigure(boolean useFileAppender) {
        /*看需要修改日志保存路径*/
        // TODO: 2018/8/6 question 需要修改文件名
        String fileName = Environment.getExternalStorageDirectory() + File.separator +
                "baseproject" + File.separator + "logs" + File.separator + "status-display.log";
        try {
            LogConfigurator logConfigurator = new LogConfigurator();
            logConfigurator.setResetConfiguration(true);
            logConfigurator.setFileName(fileName);
            logConfigurator.setRootLevel(Level.DEBUG);
            logConfigurator.setLevel("org.apache", Level.ERROR);
            //            logConfigurator.setFilePattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] [%c{2}]-[%L] %m%n");
            logConfigurator.setFilePattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] [%c{1}] %m%n");
            logConfigurator.setLogCatPattern("[%t] %m%n");
            logConfigurator.setMaxFileSize(1024 * 1024 * 5);
            logConfigurator.setUseFileAppender(useFileAppender);
            logConfigurator.setUseLogCatAppender(true);
            logConfigurator.setImmediateFlush(true);
            logConfigurator.setMaxBackupDays(5);
            logConfigurator.setMaxBackupSize(10);
            logConfigurator.setAsyncFileAppender(false);
            logConfigurator.configure();
            sLogger = LoggerFactory.getLogger(TAG);
        } catch (Exception e) {
            Log.e(TAG, "log4jConfigure", e);
        }
    }

    /**
     * 将activity加入到map中
     * @param key
     * @param weakReference
     */
    private void put(String key, WeakReference<? extends Activity> weakReference) {
        lock.lock();
        map.put(key, weakReference);
        lock.unlock();
    }

    private void remove(String key) {
        lock.lock();
        map.remove(key);
        lock.unlock();
    }

    /**
     * 结束整个程序打开的所有页面
     */
    public static void finishAllActivities() {
        lock.lock();
        for (Map.Entry<String, WeakReference<? extends Activity>> stringWeakReferenceEntry: map.entrySet()) {
            WeakReference<? extends Activity> weakReference = stringWeakReferenceEntry.getValue();
            if (weakReference.get() != null) {
                weakReference.get().finish();
            }
        }
        map.clear();
        lock.unlock();
    }

    /**
     * 监控Activity生命周期
     */
    private class ActivityLifecycle implements ActivityLifecycleCallbacks {

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            sLogger.info("onActivityCreated: " + activity.getLocalClassName());
            lastLaunched = activity.getLocalClassName();
            if (!map.containsKey(activity.getLocalClassName())) {
                WeakReference<Activity> weakReference = new WeakReference<>(activity);
                put(activity.getLocalClassName(), weakReference);
            }
        }

        @Override
        public void onActivityStarted(Activity activity) {
            sLogger.info("onActivityStarted: " + activity.getLocalClassName());
        }

        @Override
        public void onActivityResumed(Activity activity) {
            sLogger.info("onActivityResumed: " + activity.getLocalClassName());
        }

        @Override
        public void onActivityPaused(Activity activity) {
            sLogger.info("onActivityPaused: " + activity.getLocalClassName());
        }

        @Override
        public void onActivityStopped(Activity activity) {
            sLogger.info("onActivityStopped: " + activity.getLocalClassName());
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            sLogger.info("onActivitySaveInstanceState: " + activity.getLocalClassName());
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
            sLogger.info("onActivityDestroyed: " + activity.getLocalClassName());
            if (map.containsKey(activity.getLocalClassName())) {
                remove(activity.getLocalClassName());
            }
        }
    }


}
